package chatserver.netio;


import chatserver.tools.ChatException;
import chatserver.logging.ServerLog;
import chatserver.netio.Command;
import chatserver.netio.ConnectionListener;
import chatserver.netio.Connection;
import chatserver.netio.ClientAttr;
import chatserver.objects.Channel;
import chatserver.objects.Server;
import chatserver.objects.User;
import chatserver.roles.Rights;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class EventHandler implements ConnectionListener {

    public enum ConnectionStatus {

        CONNECTED, SIGNED_UP, QUIT
    }
    private Server server;
    private Connection con;
    private ConnectionStatus status;
    private User user;
    private Date lastPing;
    private static final Object sync = new Object();
    private static HashMap<Byte, Method> eventHandlers;
    private static boolean debug = true;

    {
        eventHandlers = new HashMap<Byte, Method>();
        initEventHandlers();
    }

    public EventHandler(Connection c) {
        this.con = c;
        this.server = Server.getInstance();
        this.status = ConnectionStatus.CONNECTED;
        this.user = null;
        this.lastPing = new Date();
    }
    
    public ConnectionStatus getConnectionStatus()
    {
        return status;
    }

    private static void initEventHandlers() {
        try {
            Class[] pars = new Class[1];
            pars[0] = Event.class;

            Class eh = EventHandler.class;

            eventHandlers.put(Event.NUL, eh.getMethod("handleNulEvent", pars));
            eventHandlers.put(Event.PING, eh.getMethod("handlePingEvent", pars));
            eventHandlers.put(Event.SIGNUP, eh.getMethod("handleSignUpEvent", pars));
            eventHandlers.put(Event.GETVAR, eh.getMethod("handleGetVarEvent", pars));
            eventHandlers.put(Event.RESPONSE, eh.getMethod("handleResponseEvent", pars));
            eventHandlers.put(Event.GETINFO, eh.getMethod("handleGetInfoEvent", pars));
            eventHandlers.put(Event.SETINFO, eh.getMethod("handleSetInfoEvent", pars));
            eventHandlers.put(Event.GETPERMS, eh.getMethod("handleGetPermsEvent", pars));
            eventHandlers.put(Event.CHANNELLIST, eh.getMethod("handleChannelListEvent", pars));
            eventHandlers.put(Event.JOIN, eh.getMethod("handleJoinEvent", pars));
            eventHandlers.put(Event.PART, eh.getMethod("handlePartEvent", pars));
            eventHandlers.put(Event.NOTE, eh.getMethod("handleNoteEvent", pars));
            eventHandlers.put(Event.NICKLIST, eh.getMethod("handleNickListEvent", pars));
            eventHandlers.put(Event.GETPROFILE, eh.getMethod("handleGetProfileEvent", pars));
            eventHandlers.put(Event.QUIT, eh.getMethod("handleQuitEvent", pars));
            eventHandlers.put(Event.KICK, eh.getMethod("handleKickEvent", pars));
            eventHandlers.put(Event.BAN, eh.getMethod("handleBanEvent", pars));
            eventHandlers.put(Event.UNBAN, eh.getMethod("handleUnBanEvent", pars));
            eventHandlers.put(Event.SETPROFILE, eh.getMethod("handleSetProfileEvent", pars));
            eventHandlers.put(Event.KILLCHANNEL, eh.getMethod("handleKillChannelEvent", pars));
            eventHandlers.put(Event.GETLOG, eh.getMethod("handleGetLogEvent", pars));
            eventHandlers.put(Event.REHASH, eh.getMethod("handleRehashEvent", pars));
            eventHandlers.put(Event.BANLIST, eh.getMethod("handleBanListEvent", pars));
            eventHandlers.put(Event.SETACCOUNT, eh.getMethod("handleSetAccountEvent", pars));
            eventHandlers.put(Event.FINDNICKS, eh.getMethod("handleFindNicksEvent", pars));
            eventHandlers.put(Event.REQUESTIGNORE, eh.getMethod("handleRequestIgnoreEvent", pars));
            eventHandlers.put(Event.REQUESTPRIVATE, eh.getMethod("handleRequestPrivateEvent", pars));
            eventHandlers.put(Event.EXEC, eh.getMethod("handleExecEvent", pars));
            eventHandlers.put(Event.COLORUSE, eh.getMethod("handleColorUseEvent", pars));

        } catch (NoSuchMethodException ex) {
            ex.printStackTrace();
        } catch (SecurityException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void doEvent(Event e) {

        if (eventHandlers.containsKey(e.getId())) {
            try {
                Method m = eventHandlers.get(e.getId());
                synchronized (sync) {
                    m.invoke(this, e);
                }
            } catch (IllegalAccessException ex) {
                ServerLog.logError(con, "while client event: " + ex.toString());
            } catch (IllegalArgumentException ex) {
                ServerLog.logError(con, "while client event: " + ex.toString());
            } catch (InvocationTargetException ex) {
                ServerLog.logError(con, "while client event: " + ex.getTargetException().toString());
                ex.getTargetException().printStackTrace();
            }
        } else {
            ServerLog.logWarning(con, "Unknown client event: " + e.toString());
        }

    }

    private static String getParamString(AttrList params, byte id) {
        Attr attr = params.get(id);
        if (attr == null) {
            return null;
        }
        return attr.getAsString();
    }

    private static Integer getParamInteger(AttrList params, byte id) {
        Attr attr = params.get(id);
        if (attr == null) {
            return null;
        }

        Integer ret;
        try {
            ret = attr.getInt();
        } catch (ChatException ex) {
            return null;
        }

        return ret;
    }

    private static byte[] getParamBytes(AttrList params, byte id) {
        Attr attr = params.get(id);
        if (attr == null) {
            return null;
        }

        return attr.getValue();
    }

    public void handleNulEvent(Event e) {
        String boot = getParamString(e.getParams(), ClientAttr.NUL);

        if (debug) {
            if (boot != null) {
                ServerLog.log(con, "got NUL event with boot: " + boot);
            } else {
                ServerLog.log(con, "got NUL event without boot");
            }
        }
    }

    public void handlePingEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        lastPing = new Date();
    }

    public void handleSignUpEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.CONNECTED) {
            return;
        }
        
        AttrList params = e.getParams();
        String name = getParamString(params, ClientAttr.NICKNAME);
        String password = getParamString(params, ClientAttr.PASSWORD);
        //String ident = getParamString(params, ClientAttr.IDENT);
        //String profile = getParamString(params, ClientAttr.PROFILE);
        byte[] digest = getParamBytes(params, ClientAttr.DIGEST);
        //String digestTime = getParamString(params, ClientAttr.DIGEST_TIME);
        String digestSalt = getParamString(params, ClientAttr.DIGEST_SALT);

        if (name == null) {
            return;
        }

        // A: nickname + password
        if (password != null) {
            user = server.signUpUserWithPassword(con, name, password);
        } // B: nickname + digest
        else if (digest != null) {
            user = server.signUpUserWithDigest(con, name, digest, digestSalt);
        } // C: nickname
        else {
            user = server.signUpUserAsGuest(con, name);
        }

        if (user != null) {
            this.status = ConnectionStatus.SIGNED_UP;
        }
    }

    public void handleNoteEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);
        String noteText = getParamString(params, ClientAttr.NOTE_TEXT);
        String noteFormat = getParamString(params, ClientAttr.NOTE_FORMAT);
        String noteMe = getParamString(params, ClientAttr.NOTE_ME);

        if (user.hasGlobalRight(Rights.Global.HasBoldText)) {
            if (noteFormat == null) {
                noteFormat = "\033B;";
            } else {
                noteFormat = "\033B;" + noteFormat;
            }
        }

        if (targetName != null) {
            user.sendPrivateNote(targetName, noteText, noteFormat, noteMe);
        } else if (channelName != null) {
            user.sendChannelNote(channelName, noteText, noteFormat, noteMe);
        } else {
            user.sendGlobalNote(noteText, noteFormat, noteMe);
        }

    }

    public void handleNickListEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);

        user.getNickList(channelName);
    }

    public void handleChannelListEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        user.getChannelList();
    }

    public void handleJoinEvent(Event e) {
        ServerLog.log("ADZ - EventHandler.java->handleJoinEvent");
        
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);
        String channelType = getParamString(params, ClientAttr.CHANNELTYPE);
        
        ServerLog.log("ADZ - EventHandler.java->handleJoinEvent::ChannelName="+channelName+":channelType="+channelType);

        if (channelName == null) {
            Command cmd = new Command(Command.NOCHANNEL);
            con.sendCommand(cmd);
            return;
        }

        Channel c = server.findChannel(channelName);
        
        ServerLog.log("ADZ - EventHandler.java->handleJoinEvent::Channel="+c);
        
        if (c != null) {
            user.joinChannel(c);
        } else {
            user.createAndJoinChannel(channelName, channelType);
        }

    }

    public void handlePartEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got PART event(" + e.toString() + ")");
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);

        if (channelName == null) {
            Command cmd = new Command(Command.NOCHANNEL);
            con.sendCommand(cmd);
            return;
        }

        Channel c = server.findChannel(channelName);
        if (c != null) {
            user.partChannel(c);
        }
    }

    public void handleRehashEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        user.doRehash();
    }

    public void handleGetInfoEvent(Event e) {
        ServerLog.log("ADZ - EvantHandler.java->handleGetInfoEvent:params=:"+e.getParams());
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);

        if (targetName != null) {
            if (channelName != null) {
                user.getMemberInfo(channelName, targetName);
            } else {
                user.getUserInfo(targetName);
            }
        } else {
            if (channelName != null) {
                user.getChannelInfo(channelName);
            } else {
                user.getChatBoxInfo();
            }
        }
    }

    public void handleSetInfoEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);
        String sIndex = getParamString(params, ClientAttr.INDEX);
        Integer index = null;
        if (sIndex != null) {
            index = Integer.valueOf(sIndex);
        }

        ServerLog.log("ADZ - EventHandler.java->handleSetInfoEvent:targetName=" + targetName + ":channelname=" + channelName + ":index=" + index);
        
        if (targetName != null) {
            if (channelName != null) {
                user.setMemberInfo(channelName, targetName, params.toArray(ClientAttr.MEMBERINFO), index);
            } else {
                user.setUserInfo(targetName, params.toArray(ClientAttr.USERINFO), index);
            }
        } else {
            if (channelName != null) {
                user.setChannelInfo(channelName, params.toArray(ClientAttr.CHANNELINFO), index);
            } else {
                user.setChatBoxInfo(params.toArray(ClientAttr.CHATBOXINFO), index);
            }
        }
    }

    public void handleKickEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);

        if (targetName == null) {
            Command cmd = new Command(Command.NOTARGET);
            con.sendCommand(cmd);
            return;
        }

        if (channelName != null) {
            user.channelKick(channelName, targetName);
        } else {
            user.serverKick(targetName);
        }

    }

    public void handleBanEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);

        if (targetName == null) {
            Command cmd = new Command(Command.NOTARGET);
            con.sendCommand(cmd);
            return;
        }

        String channelName = getParamString(params, ClientAttr.CHANNELNAME);
        String profile = getParamString(params, ClientAttr.PROFILE);


        if (profile == null || profile.toLowerCase().equals("banned")) {

            Integer iIpSize = getParamInteger(params, ClientAttr.BAN_IPSIZE);
            Integer iTimeLeft = getParamInteger(params, ClientAttr.BAN_TIMELEFT);

            int ipSize = 32;
            if (iIpSize != null) {
                ipSize = iIpSize;
            }

            if (channelName != null) {

                int timeLeft = 3600 * 24;
                if (iTimeLeft != null) {
                    timeLeft = iTimeLeft;
                }

                Date d = new Date();
                long expires = (d.getTime() / 1000) + timeLeft;

                user.channelBan(channelName, targetName, ipSize, expires);
            } else {
                int timeLeft = 3600 * 72;
                if (iTimeLeft != null) {
                    timeLeft = iTimeLeft;
                }

                Date d = new Date();
                long expires = (d.getTime() / 1000) + timeLeft;
                user.serverBan(targetName, ipSize, expires);
            }
        } else {
            if (channelName != null) {
                user.channelOp(channelName, targetName, profile, true);
            } else {
                user.serverOp(targetName, profile, true);
            }
        }

    }

    public void handleUnBanEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);

        if (targetName == null) {
            Command cmd = new Command(Command.NOTARGET);
            con.sendCommand(cmd);
            return;
        }

        String channelName = getParamString(params, ClientAttr.CHANNELNAME);
        String profile = getParamString(params, ClientAttr.PROFILE);

        if (profile != null && profile.toLowerCase().equals("banned")) {
            if (channelName != null) {
                user.channelUnBan(channelName, targetName);
            } else {
                user.serverUnBan(targetName);
            }
        } else {
            if (channelName != null) {
                user.channelDeOp(channelName, targetName, true);
            } else {
                user.serverDeOp(targetName, true);
            }
        }
    }

    public void handleBanListEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String profile = getParamString(params, ClientAttr.PROFILE);
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);

        boolean isBanList = false;
        if (profile != null) {
            isBanList = profile.toLowerCase().equals("banned");
        }

        if (isBanList) {
            if (channelName == null) {
                user.getServerBanList();
            } else {
                user.getChannelBanList(channelName);
            }
        } else {
            if (channelName == null) {
                user.getServerAutoOpList();
            } else {
                user.getChannelAutoOpList(channelName);
            }
        }

    }

    public void handleQuitEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        this.status = ConnectionStatus.QUIT;
        con.close();
    }

    public void handleGetVarEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String varName = getParamString(params, ClientAttr.VARNAME);

        if (varName == null) {
            return;
        }

        if (varName.equals("allowedhosts")) {
            List<String> aHosts = server.getConfig().getAllowedHosts();

            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.VARNAME, "allowedhosts");
            for (String host : aHosts) {
                at.safeAddClientAttr(ClientAttr.VARVALUE, host);
            }
            con.sendCommand(new Command(Command.VARIABLE, at));
        }

    }

    public void handleGetPermsEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);

        if (targetName != null) {
            if (channelName != null) {
                user.getChannelUserPerms(channelName, targetName);
            } else {
                user.getGlobalUserPerms(targetName);
            }
        }
    }

    public void handleKillChannelEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);

        if (channelName == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        user.killChannel(channelName);
    }

    public void handleSetProfileEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);
        String profile = getParamString(params, ClientAttr.PROFILE);

        if (targetName == null) {
            Command cmd = new Command(Command.NOTARGET);
            con.sendCommand(cmd);
            return;
        }

        if (profile != null && profile.toLowerCase().equals("banned")) {
            if (channelName != null) {
                user.channelKick(channelName, targetName);
            } else {
                user.serverKick(targetName);
            }
        } else {
            if (profile == null) {
                if (channelName != null) {
                    user.channelDeOp(channelName, targetName, false);
                } else {
                    user.serverDeOp(targetName, false);
                }
            } else {
                if (channelName != null) {
                    user.channelOp(channelName, targetName, profile, false);
                } else {
                    user.serverOp(targetName, profile, false);
                }
            }
        }

    }

    public void handleGetProfileEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        String channelName = getParamString(params, ClientAttr.CHANNELNAME);

        if (targetName == null) {
            Command cmd = new Command(Command.NOTARGET);
            con.sendCommand(cmd);
            return;
        }

        User target = server.findUser(targetName);
        if (target == null) {
            Command cmd = new Command(Command.NOTARGET);
            con.sendCommand(cmd);
            return;
        }

        if (channelName != null) {
            Channel c = server.findChannel(channelName);
            if (c == null) {
                AttrList at = new AttrList();
                at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
                Command cmd = new Command(Command.NOCHANNEL, at);
                con.sendCommand(cmd);
                return;
            }
            String profile = c.getUserChannelProfile(target);
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.NICKNAME, targetName);
            at.safeAddClientAttr(ClientAttr.PROFILE, profile);
            con.sendCommand(new Command(Command.PROFILE, at));
        } else {
            String profile = target.getGlobalProfile();
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.NICKNAME, targetName);
            at.safeAddClientAttr(ClientAttr.PROFILE, profile);
            con.sendCommand(new Command(Command.PROFILE, at));
        }

    }

    public void handleResponseEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.CONNECTED) {
            return;
        }

        String name;
        byte[] digest;
        String digestSalt;

        // response to ChallengeePassword
        if (con.getTmpDigestSalt() != null) {

            name = con.getTmpLoginName();
            digestSalt = con.getTmpDigestSalt();
            AttrList params = e.getParams();
            digest = getParamBytes(params, ClientAttr.DIGEST);

        } // response to ChallengeeID
        else {
            AttrList params = e.getParams();
            byte[] bytesRealParams = getParamBytes(params, ClientAttr.DIGEST);
            InputStream istream = new ByteArrayInputStream(bytesRealParams);
            AttrList realParams;
            try {
                realParams = new AttrList(ClientAttr.getProto(), istream, bytesRealParams.length);
            } catch (Exception ex) {
                ServerLog.log(con, "kicking client because of malformed response to ChallengeeID");
                con.close();
                return;
            }

            name = getParamString(realParams, ClientAttr.NICKNAME);
            digest = getParamBytes(realParams, ClientAttr.DIGEST);
            digestSalt = getParamString(realParams, ClientAttr.DIGEST_SALT);
            //Integer digestTime = getParamInteger(realParams, ClientAttr.DIGEST_TIME);
        }

        if (name == null || digestSalt == null || digest == null) {
            return;
        }
        user = server.signUpUserWithDigest(con, name, digest, digestSalt);

        if (user != null) {
            this.status = ConnectionStatus.SIGNED_UP;
        }

    }

    public void handleGetLogEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }
        AttrList params = e.getParams();
        Integer iLogTime = getParamInteger(params, ClientAttr.LOG_TIME);

        int logTime = 0;
        if (iLogTime != null) {
            logTime = iLogTime;
        }

        user.getChannelLog(logTime);
    }

    public void handleSetAccountEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String name = getParamString(params, ClientAttr.NICKNAME);
        String password = getParamString(params, ClientAttr.PASSWORD);
        String email = getParamString(params, ClientAttr.USERINFO);

        if (name == null || password == null || email == null) {
            con.sendCommand(new Command(Command.REGMISSING));
            return;
        }

        user.setAccount(name, password, email);
    }

    public void handleFindNicksEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String name = getParamString(params, ClientAttr.NICKNAME);
        String channel = getParamString(params, ClientAttr.CHANNELNAME);
        String profile = getParamString(params, ClientAttr.PROFILE);
        Attr[] aUserinfo = params.toArray(ClientAttr.USERINFO);

        String[] userInfo = new String[5];

        for (int i = 0; i < userInfo.length && i < aUserinfo.length; i++) {
            String nfo = aUserinfo[i].getAsString();
            if (nfo != null) {
                userInfo[i] = nfo;
            }
        }

        List<User> userList;

        if (channel == null) {
            userList = server.findUsers(name, profile, userInfo);
        } else {
            Channel c = server.findChannel(channel);
            if (c == null) {
                AttrList at = new AttrList();
                at.safeAddClientAttr(ClientAttr.CHANNELNAME, channel);
                Command cmd = new Command(Command.NOCHANNEL, at);
                con.sendCommand(cmd);
                return;
            }
            userList = c.findUsers(name, profile, userInfo);
        }

        AttrList at = new AttrList();
        Iterator<User> iter = userList.iterator();
        while (iter.hasNext()) {
            User u = iter.next();
            if (u.isHidden()) {
                continue;
            }
            at.safeAddClientAttr(ClientAttr.NICKNAME, u.getName());
            try {
                at.add(u.getGlobalPerms().toAttr(ClientAttr.PERMS));
            } catch (Exception ex) {
            }
            at.safeAddClientAttr(ClientAttr.PROFILE, u.getGlobalProfile());
        }
        Command cmd = new Command(Command.NICKLIST, at);
        con.sendCommand(cmd);
    }

    public void handleRequestIgnoreEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        if (targetName == null) {
            return;
        }
        
        if (user.getName().equalsIgnoreCase(targetName)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }
        
        
        if (server.findUser(targetName) == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
        Command cmd = new Command(Command.ADDIGNORE, at);
        con.sendCommand(cmd);
    }

    public void handleRequestPrivateEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        if (this.status != ConnectionStatus.SIGNED_UP) {
            return;
        }

        AttrList params = e.getParams();
        String targetName = getParamString(params, ClientAttr.TARGETNAME);
        if (targetName == null) {
            return;
        }
        
        if (user.getName().equalsIgnoreCase(targetName)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }
        
        if (server.findUser(targetName) == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }


        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
        Command cmd = new Command(Command.OPENPRIVATE, at);
        con.sendCommand(cmd);
    }

    public void handleExecEvent(Event e) {
        if (debug) {
            ServerLog.log(con, "got " + e.toString());
        }

        String exec = getParamString(e.getParams(), ClientAttr.EXEC);
        if (exec == null) {
            exec = "(null)";
        }

        ServerLog.log(con, "Client-Exception: " + exec);
    }
    
     public void handleColorUseEvent(Event e) {
        ServerLog.log("ADZ - EventHandler.java->handleColorUseEvent:user="+this.user.getName()+":AttrList="+e.getParams());
        
        AttrList at = e.getParams();
        try {
            at.add(new ClientAttr(ClientAttr.VARVALUE, "" + this.user.isGuest()));
        } catch (ChatException ex) {
            Logger.getLogger(EventHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
        this.con.sendCommand(new Command(Command.COLORUSE, at));
    }

    //
    // Unsupported events as of now
    //
    // Queuing
    public void handleAutoqueueEvent(Event e) {
    }

    public void handleEnqueueEvent(Event e) {
    }

    public void handleDequeueEvent(Event e) {
    }

    // Proxy listing
    public void handleProxyListEvent(Event e) {
    }

    // Unused perm events
    public void handleGivePermsEvent(Event e) {
    }

    public void handleTakePermsEvent(Event e) {
    }

    @Override
    public void connectionClosed(Connection con) {

        if (user != null) {
            user.onDisconnect();
        }

        server.onConnectionClosed(con);
    }
}
